import {Logger} from "log4js";
import {CARDS_TO_ASCII_STR, Comb, EndType, GAME_STEP, MAX_HAND_CARD, PlayerAction} from "./GameDefine";
import {GameData} from "./GameData";
import {GameLogic} from "./GameLogic";
import {Table} from "../table";
import {Player} from "../player";
import {cmd} from "../../../config/cmd";
import {randInt} from "../../util/util";
import {I_gameMgr} from "../gameMgr";

export default class GameMgr implements I_gameMgr{
    private log:Logger;
    private gameStep:GAME_STEP;
    private gameData:GameData;
    private gameLogic:GameLogic;
    private playerCount;
    private table:Table;
    private countDown:number;
    private takeFirstTime=5*1000;
    private playCardTime=15*1000;
    private winLostTime=2*1000;
    private rank:number[];
    private waitFeng:boolean; //等待接风标志
    private fengSuccess:boolean; //接风成功标志
    init(table:Table,rule: { playerCount: number,rule?:string }) {
        this.table = table;
        this.log=this.table.getTableLogger();
        this.playerCount = rule.playerCount;
        this.gameData = new GameData();
        this.gameLogic = new GameLogic();
    }

    update(dt) {
        this.countDown-=dt;
        if(this.countDown>0){
            return;
        }
        if(this.gameStep == GAME_STEP.TAKE_FIRST){
            this.playCard();
        }else if(this.gameStep == GAME_STEP.PLAY_CARD){
            this.outCardTimeOut();
        }else if(this.gameStep == GAME_STEP.WIN_LOST){
            this.gameEnd();
        }
    }

    //是否能开始游戏
    canGameStart():boolean{
        //人未满不开桌
        if(this.table.getPlayerCount()<this.playerCount){
            return false
        }
        let players = this.table.getAllPlayer();
        //所有人必须准备游戏
        for (var i=0;i<players.length;i++){
            if(players && !players[i].isReady()){
                return false;
            }
        }
        return true;
    }

    onGameStart() {
        this.reset();
        this.sendGameStart();
        this.takeFirst();
    }

    //一般这个只是为了处理断线重连
    onEnterTable(player: Player) {
        if(this.table.isGameProcessing() && this.gameStep<=GAME_STEP.PLAY_CARD){
            this.sendMsgToPlayer("game_reconnect",null,player);
            this.sendHandCard(player);
            if(this.gameStep==GAME_STEP.PLAY_CARD){
                this.sendRound(player);
                this.sendAllAction(player);
                this.sendPower(player);
                this.sendClock();
                this.sendRank(player);
            }
            this.sendMsgToPlayer("game_reconnect_over",null,player);
        }
    }

    onReceiveMessage(player:Player,msg: { event: string; data: any }) {
        if(msg.event == "game_action"){
            this.onGameAction(player,msg.data);
        }
    }

    sendMsgToAll(event: string, data: any = null) {
        this.table.sendMsgToAll(cmd.game_main_msg,{event:event,data:data});
    }

    sendMsgToPlayer(event: string, data: any = null,player:Player) {
        this.table.sendMsgToPlayer(cmd.game_main_msg,{event:event,data:data},player);
    }

    sendMsgToOthers(event: string, data: any = null,player:Player) {
        this.table.sendMsgToOthers(cmd.game_main_msg,{event:event,data:data},player);
    }
    /////////////////////////////////////////////////////////////////
    private reset(){
        this.gameStep = GAME_STEP.GAME_START;
        this.gameData.reset();
        this.gameLogic.reset();
        this.gameLogic.init_sk();
        this.rank = [];
        this.waitFeng = false;
        this.fengSuccess = false;
    }

    /**
     * 获取下一个可以出牌的玩家。
     * @param seat
     */
    private getNextPlayer(seat:number):Player{
        let players = this.table.getAllPlayer();
        for(var i=seat+1;i<players.length;i++){
            var player = players[i];
            if(player && player.isPlaying() && this.gameData.handCards[player.seat].length>0){
                return player;
            }
        }
        for(var i=0;i<seat;i++){
            var player = players[i];
            if(player && player.isPlaying() && this.gameData.handCards[player.seat].length>0){
                return player;
            }
        }
    }

    /**
     * 获取前一个可以出牌的玩家
     * @param seat
     */
    private getPrePlayer(seat:number):Player{
        let players = this.table.getAllPlayer();
        for(var i=seat-1;i>=0;i--){
            var player = players[i];
            if(player && player.isPlaying() && this.gameData.handCards[player.seat].length>0){
                return player;
            }
        }
        for(var i=players.length-1;i>seat;i--){
            var player = players[i];
            if(player && player.isPlaying() && this.gameData.handCards[player.seat].length>0){
                return player;
            }
        }
    }

    private getPlayerBySeat(seat:number):Player{
        let players = this.table.getAllPlayer();
        return players[seat];
    }
    /**
     * 获取对家位子
     * @param seat
     */
    private getPartnerSeat(seat:number){
        return (seat+2)%4;
    }

    //抓牌
    private takeFirst() {
        this.gameStep = GAME_STEP.TAKE_FIRST;
        this.gameLogic.suffer();
        let players = this.table.getAllPlayer();
        for (var i=0;i<players.length;i++){
            var player = players[i];
            if(player && players[i].isPlaying()){
                for(var j=0;j<MAX_HAND_CARD;j++){
                    this.gameData.handCards[player.seat][j] = this.gameLogic.getACard();
                }
                this.gameLogic.sort_cards_by_size_up(this.gameData.handCards[player.seat]);
                this.log.info("uid=%d,seat=%d hand cards=",player.uid,player.seat,CARDS_TO_ASCII_STR(this.gameData.handCards[player.seat]))
            }
        }
        for (var i=0;i<players.length;i++){
            var player = players[i];
            if(player && players[i].isPlaying()){
                this.sendHandCard(player);
            }
        }
        //抓牌
        this.sendTakeFirst();
        this.countDown = this.takeFirstTime;
    }

    //TODO 换位子
    private changeSeat() {
        this.gameStep = GAME_STEP.CHANGE_SEAT;
    }

    //打牌
    private playCard() {
        this.gameStep = GAME_STEP.PLAY_CARD;
        if(this.gameData.preSeat == null){
            let player = this.getNextPlayer(randInt(this.playerCount))
            this.gameData.roundCurSeat  = player.seat;
            this.gameData.roundCurPower = PlayerAction.PLAY;
        }else if(this.fengSuccess){
            this.waitFeng = false;
            this.fengSuccess = false;
            //接风特殊处理
            this.gameData.roundCurSeat  = this.getPartnerSeat(this.gameData.preSeat)
            this.gameData.roundCurPower = PlayerAction.PLAY;
            this.gameData.resetRound();
        }else{
            let player = this.getNextPlayer(this.gameData.roundCurSeat)
            this.gameData.roundCurSeat  = player.seat;
            this.gameData.roundCurPower = PlayerAction.PLAY + PlayerAction.NOT_PLAY;
            //如果最后一个出牌的是自己
            if(this.gameData.preSeat == player.seat){
                this.gameData.resetRound();
                this.gameData.roundCurPower -= PlayerAction.NOT_PLAY;
            }
        }
        this.sendRound();
        this.sendPower();
        this.countDown = this.playCardTime;
        this.sendClock()
    }

    //出牌超时
    private outCardTimeOut(){
        if((this.gameData.roundCurPower&PlayerAction.NOT_PLAY)>0){
            this.dealOutCard(this.gameData.roundCurSeat,PlayerAction.NOT_PLAY);
        }else {
            //TODO 超时暂时只出一张牌
            this.gameLogic.sort_cards_by_size_up(this.gameData.handCards[this.gameData.roundCurSeat]);
            let combs = this.gameLogic.get_all_combs([this.gameData.handCards[this.gameData.roundCurSeat][0]])
            this.dealOutCard(this.gameData.roundCurSeat,PlayerAction.PLAY,combs[0]);
        }
    }

    //结算
    private winLost() {
        this.gameStep = GAME_STEP.WIN_LOST;
        this.sendAllHandCard();
        var msg:any = {};
        var base = 1;
        msg.rank = this.rank;
        if(this.rank[0] == this.getPartnerSeat(this.rank[1])){
            msg.endType = EndType.END_SHUANGKOU;
            msg.rank[2] = (msg.rank[0]+1)%4;
            msg.rank[3] = this.getPartnerSeat(msg.rank[2])
            base = 3;
        }else if(this.rank[0] == this.getPartnerSeat(this.rank[2])){
            msg.endType = EndType.END_DANKOU;
            this.rank[3] = this.getPartnerSeat(msg.rank[1])
            base = 2;
        }else{
            msg.endType = EndType.END_PINGKOU;
            this.rank[3] = this.getPartnerSeat(msg.rank[0])
            base = 1;
        }
        msg.score = [];
        let players = this.table.getAllPlayer();
        for (var i=0;i<players.length;i++){
            var player = players[i];
            if(player && players[i].isPlaying()){
                if(player.seat==this.rank[0] || player.seat==this.getPartnerSeat(this.rank[0])){
                    msg.score[player.seat] = base*10;
                }else{
                    msg.score[player.seat] = -base*10;
                }
            }
        }
        this.sendWinLost(msg);
        this.countDown = this.winLostTime;
    }

    //游戏结束
    private gameEnd() {
        this.gameStep = GAME_STEP.GAME_END;
        //通知桌子游戏结束
        this.table.onGameOver();
    }

    private sendGameStart(){
        this.sendMsgToAll("game_start")
    }

    private sendGameStep(){
        this.sendMsgToAll("game_step",{step:this.gameStep})
    }

    private sendTakeFirst(){
        this.sendMsgToAll("game_take_first")
    }

    //发送手牌
    private sendHandCard(player:Player){
        let players = this.table.getAllPlayer();
        for (let i=0;i<players.length;i++){
            if(!players[i]){
                continue;
            }
            if(players[i]==player){
                //发送自己的牌给自己
                this.sendMsgToPlayer("game_hand_card",{seat:player.seat,cards:this.gameData.handCards[player.seat]},player);
            }else if(players[i].isPlaying()){
                //发送别人的牌背给自己
                this.sendMsgToPlayer("game_hand_back",{seat:i,count:this.gameData.handCards[players[i].seat].length},player);
            }
        }
    }

    private sendRound(player?:Player){
        if(player){
            this.sendMsgToPlayer("game_round",{preComb:this.gameData.preComb,preSeat:this.gameData.preSeat},player)
        }else{
            this.sendMsgToAll("game_round",{preComb:this.gameData.preComb,preSeat:this.gameData.preSeat})
        }
    }

    private sendPower(player?:Player){
        if(player){
            this.sendMsgToPlayer("game_power",{seat:this.gameData.roundCurSeat,power:this.gameData.roundCurPower},player)
        }else{
            this.sendMsgToAll("game_power",{seat:this.gameData.roundCurSeat,power:this.gameData.roundCurPower})
        }
    }

    private dealOutCard(seat,action:PlayerAction,comb?:Comb){
        this.gameData.action[seat] = action;
        if(comb){
            this.gameData.outCards[seat] = comb.cards;
        }
        if(action==PlayerAction.NOT_PLAY){
            this.log.info("uid=%d,seat=%d not out",this.getPlayerBySeat(seat).uid,seat)
            this.sendMsgToAll("game_action",{seat:seat,action:action});
            if(this.waitFeng){
                let prePlayer = this.getPrePlayer(this.gameData.preSeat);
                if(prePlayer.seat==seat){
                    this.fengSuccess = true;
                }
            }
        }else{
            this.log.info("uid=%d,seat=%d out card=",this.getPlayerBySeat(seat).uid,seat,CARDS_TO_ASCII_STR(comb.cards))
            this.gameData.preSeat = seat;
            this.gameData.preComb = comb;
            this.gameLogic.del_sub_cards(this.gameData.handCards[seat],comb.cards);
            this.sendMsgToAll("game_action",{seat:seat,action:action,comb:comb});
            if(this.waitFeng){
                //中途有人出牌停止接风
                this.waitFeng = false;
            }
            //手牌打完
            if(this.gameData.handCards[seat].length==0){
                //刷新接风标志
                this.waitFeng = true;
                this.fengSuccess = false;
                //发送排名
                this.rank.push(seat);
                this.sendRank();
            }
        }
        if(this.rank.length==this.playerCount-1 || this.rank[0]==this.getPartnerSeat(this.rank[1])){
            this.winLost();
        }else {
            this.playCard();
        }
    }

    private sendClock(player?:Player){
        if(player){
            this.sendMsgToPlayer("game_clock",{seat:this.gameData.roundCurSeat,time:Math.floor(this.playCardTime/1000),remain:Math.floor(this.countDown/1000)},player)
        }else{
            this.sendMsgToAll("game_clock",{seat:this.gameData.roundCurSeat,time:Math.floor(this.playCardTime/1000),remain:Math.floor(this.countDown/1000)})
        }
    }

    private sendRank(player?:Player){
        if(this.rank.length==0){
            return;
        }
        if(player){
            this.sendMsgToPlayer("game_rank",{rank:this.rank},player)
        }else{
            this.sendMsgToAll("game_rank",{rank:this.rank})
        }
    }

    private sendAllAction(player:Player){
        this.sendMsgToPlayer("game_all_action",{action:this.gameData.action,cards:this.gameData.outCards},player)
    }

    private sendAllHandCard(){
        this.sendMsgToAll("game_all_hands",{cards:this.gameData.handCards})
    }

    private sendWinLost(msg:any){
        this.sendMsgToAll("game_win_lost",msg)
    }
    //////////////////////////////////////////////////////////////////////////////////////////////
    private onGameAction(player:Player,data:{ action:PlayerAction, comb?:Comb}){
        if(player.seat!=this.gameData.roundCurSeat){
            return;
        }
        if((this.gameData.roundCurPower&data.action)==0){
            return;
        }
        if(data.action==PlayerAction.NOT_PLAY){
            this.dealOutCard(player.seat,data.action)
            return;
        }
        //验证手牌
        if(!this.gameLogic.is_sub_cards(this.gameData.handCards[player.seat],data.comb.cards)){
            return;
        }
        //验证牌型
        if(!this.gameLogic.checkComb(data.comb)){
            return;
        }
        //验证大小
        if(this.gameData.preComb==null || this.gameLogic.compare_two_comb(data.comb,this.gameData.preComb)){
            this.dealOutCard(player.seat,data.action,data.comb)
        }
    }
}